
package com.jf.cloud.payment.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.leaf.feign.SegmentFeignClient;
import com.jf.cloud.api.multishop.feign.ShopWalletLogFeignClient;
import com.jf.cloud.api.order.constant.FinanceType;
import com.jf.cloud.api.order.constant.OrderStatus;
import com.jf.cloud.api.order.feign.OrderFeignClient;
import com.jf.cloud.api.order.vo.AccountOrderDetailVO;
import com.jf.cloud.api.order.vo.OrderAmountVO;
import com.jf.cloud.api.order.vo.PageShopAccountOrderVO;
import com.jf.cloud.api.order.vo.ShopAccountOrderDetailVO;
import com.jf.cloud.api.payment.vo.AccountDetailVO;
import com.jf.cloud.api.payment.vo.ShopAccountDetailVO;
import com.jf.cloud.api.user.bo.BuyVipNotifyBO;
import com.jf.cloud.api.user.bo.RechargeNotifyBO;
import com.jf.cloud.api.user.bo.UserScoreBO;
import com.jf.cloud.api.user.feign.UserBalanceLogClient;
import com.jf.cloud.api.user.feign.UserLevelLogClient;
import com.jf.cloud.api.user.vo.UserPayInfoVO;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.constant.DistributedIdKey;
import com.jf.cloud.common.constant.PayType;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.bo.EsOrderBO;
import com.jf.cloud.common.order.bo.PayNotifyBO;
import com.jf.cloud.common.product.constant.PreSaleType;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.common.util.Arith;
import com.jf.cloud.common.util.ExcelUtil;
import com.jf.cloud.common.util.PriceUtil;
import com.jf.cloud.payment.bo.PayInfoBO;
import com.jf.cloud.payment.bo.PayInfoResultBO;
import com.jf.cloud.payment.constant.PayEntry;
import com.jf.cloud.payment.constant.PayStatus;
import com.jf.cloud.payment.dto.AccountSearchDTO;
import com.jf.cloud.payment.dto.BuyVipPayInfoDTO;
import com.jf.cloud.payment.dto.PayInfoDTO;
import com.jf.cloud.payment.dto.RechargePayInfoDTO;
import com.jf.cloud.payment.mapper.PayInfoMapper;
import com.jf.cloud.payment.model.PayInfo;
import com.jf.cloud.payment.service.PayInfoService;
import com.jf.cloud.payment.vo.PayInfoExcelVO;
import com.jf.cloud.payment.vo.PayInfoVO;
import ma.glasnost.orika.MapperFacade;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 订单支付记录
 *
 * @author zz
 * @date 2020-12-25 09:50:59
 */
@Service
public class PayInfoServiceImpl implements PayInfoService {
    private static final Logger log = LoggerFactory.getLogger(PayInfoServiceImpl.class);

    @Autowired
    private PayInfoMapper payInfoMapper;

    @Autowired
    private SegmentFeignClient segmentFeignClient;

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Autowired
    private RocketMQTemplate orderNotifyTemplate;

    @Autowired
    private RocketMQTemplate userRechargeNotifyTemplate;

    @Autowired
    private RocketMQTemplate shopRechargeNotifyTemplate;

    @Autowired
    private UserBalanceLogClient userBalanceLogClient;

    @Autowired
    private ShopWalletLogFeignClient shopWalletLogFeignClient;

    @Autowired
    private UserLevelLogClient userLevelLogClient;

    @Autowired
    private RocketMQTemplate buyVipNotifyTemplate;

    @Autowired
    private RocketMQTemplate userScoreTemplate;

    @Autowired
    private MapperFacade mapperFacade;



    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayInfoBO pay(Long userId, PayInfoDTO payParam) {
        // 支付单号
        ServerResponseEntity<Long> segmentIdResponse = segmentFeignClient.getSegmentIdWithDateTime(DistributedIdKey.MALL4CLOUD_PAY, userId);
        if (!segmentIdResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        Long payId = segmentIdResponse.getData();

        List<Long> orderIds = payParam.getOrderIds();
        ServerResponseEntity<OrderAmountVO> ordersAmountAndIfNoCancelResponse = orderFeignClient.getOrdersAmountAndIfNoCancel(orderIds);
        // 如果订单已经关闭了，此时不能够支付了
        if (ordersAmountAndIfNoCancelResponse.isFail()) {
            throw new LuckException(ordersAmountAndIfNoCancelResponse.getMsg());
        }
        OrderAmountVO orderAmount = ordersAmountAndIfNoCancelResponse.getData();

        //如果金额小于0.01 支付积分大于0则为纯积分支付
        if (orderAmount.getPayAmount() < 1 && orderAmount.getPayScore() > 0 && !Objects.equals(PayType.SCOREPAY.value(), payParam.getPayType())) {
            throw new LuckException("订单金额有误，无法进行支付");
        }
        // 金额小于0.01且支付方式不为积分支付
        else if (orderAmount.getPayAmount() < 1 && !Objects.equals(PayType.SCOREPAY.value(), payParam.getPayType())) {
            throw new LuckException("订单金额有误，无法进行支付");
        }
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setUserId(userId);
        payInfo.setPayAmount(orderAmount.getPayAmount());
        payInfo.setPayScore(orderAmount.getPayScore());
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setSysType(AuthUserContext.get().getSysType());
        payInfo.setPayType(payParam.getPayType());
        payInfo.setVersion(0);
        // 保存多个支付订单号
        payInfo.setOrderIds(StrUtil.join(StrUtil.COMMA, orderIds));

        payInfo.setPayEntry(PayEntry.ORDER.value());
        // 保存预支付信息
        payInfoMapper.save(payInfo);
        PayInfoBO payInfoBo = new PayInfoBO();
        payInfoBo.setBody("商城支付订单");
        payInfoBo.setPayAmount(orderAmount.getPayAmount());
        payInfoBo.setPayId(payId);
        payInfoBo.setOrderIds(payInfo.getOrderIds());
        return payInfoBo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayInfoBO payPreSaleBalance(Long userId, PayInfoDTO payParam) {
        // 支付单号
        ServerResponseEntity<Long> segmentIdResponse = segmentFeignClient.getSegmentIdWithDateTime(DistributedIdKey.MALL4CLOUD_PAY, userId);
        if (!segmentIdResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        Long payId = segmentIdResponse.getData();

        List<Long> orderIds = payParam.getOrderIds();
        ServerResponseEntity<OrderAmountVO> ordersAmountAndIfNoCancelResponse = orderFeignClient.getOrdersAmountAndCheckOrderStatus(orderIds);
        // 如果订单不是代付尾款状态，此时不能够支付了
        if (!ordersAmountAndIfNoCancelResponse.isSuccess()) {
            throw new LuckException(ordersAmountAndIfNoCancelResponse.getMsg());
        }
        OrderAmountVO orderAmount = ordersAmountAndIfNoCancelResponse.getData();
        //如果金额小于0.01 支付积分大于0则为纯积分支付
        if (orderAmount.getPayAmount() < 1 && orderAmount.getPayScore() > 0 && !Objects.equals(PayType.SCOREPAY.value(), payParam.getPayType())) {
            throw new LuckException("订单金额有误，无法进行支付");
        }
        // 金额小于0.01且支付方式不为积分支付
        else if (orderAmount.getPayAmount() < 1 && !Objects.equals(PayType.SCOREPAY.value(), payParam.getPayType())) {
            throw new LuckException("订单金额有误，无法进行支付");
        }
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setUserId(userId);
        payInfo.setPayAmount(orderAmount.getPayAmount());
        payInfo.setPayScore(orderAmount.getPayScore());
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setSysType(AuthUserContext.get().getSysType());
        payInfo.setPayType(payParam.getPayType());
        payInfo.setVersion(0);
        // 保存多个支付订单号
        payInfo.setOrderIds(StrUtil.join(StrUtil.COMMA, orderIds));

        payInfo.setPayEntry(PayEntry.ORDER.value());
        // 保存预支付信息
        payInfoMapper.save(payInfo);
        PayInfoBO payInfoBo = new PayInfoBO();
        payInfoBo.setBody("商城支付订单");
        payInfoBo.setPayAmount(orderAmount.getPayAmount());
        payInfoBo.setPayId(payId);
        return payInfoBo;
    }

    @Override
    public PayInfo getByPayId(Long payId) {
        return payInfoMapper.getByPayId(payId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(PayInfoResultBO payInfoResult, PayInfo temp, List<Long> orderIds) {
        // 标记为支付成功状态
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payInfoResult.getPayId());
        payInfo.setBizPayNo(payInfoResult.getBizPayNo());
        payInfo.setCallbackContent(payInfoResult.getCallbackContent());
        payInfo.setCallbackTime(new Date());
        payInfo.setPayStatus(PayStatus.PAYED.value());
        payInfoMapper.update(payInfo);

        // 发送消息，订单支付成功
        SendStatus sendStatus = orderNotifyTemplate.syncSend(RocketMqConstant.ORDER_NOTIFY_TOPIC, new GenericMessage<>(new PayNotifyBO(orderIds, PayType.instance(temp.getPayType()).value(), payInfo.getPayId()))).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，因为订单回调会有多次，几乎不可能每次都无法发送出去，发的出去无所谓因为接口是幂等的
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        //TODO 收款码订单积分服务啥也不干
        UserScoreBO userScoreBo = new UserScoreBO();
        userScoreBo.setUserId(temp.getUserId());
        userScoreBo.setPayType(payInfo.getPayType());
        userScoreBo.setOrderIds(orderIds);
        SendStatus userScoreSendStatus = userScoreTemplate.syncSend(RocketMqConstant.SCORE_UNLOCK_TOPIC, new GenericMessage<>(userScoreBo)).getSendStatus();
        if (!Objects.equals(userScoreSendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，发的出去无所谓
            throw new LuckException(ResponseEnum.EXCEPTION);
        }


    }



    @Override
    public Integer getPayStatusByOrderIds(String orderIds) {
        return payInfoMapper.getPayStatusByOrderIds(orderIds);
    }

    @Override
    public Integer isPay(String orderIds, Long userId, Integer payEntry) {
        Integer sysType = AuthUserContext.get().getSysType();
        String[] orderIdList = orderIds.split(StrUtil.COMMA);
        ServerResponseEntity<EsOrderBO> orderResp = orderFeignClient.getEsOrder(Long.valueOf(orderIdList[0]));
        if (orderResp.isFail()) {
            throw new LuckException(orderResp.getMsg());
        }
        if (Objects.nonNull(orderResp.getData())) {
            EsOrderBO esOrderBO = orderResp.getData();
            // 如果是定金支付，且为待付尾款状态，则为未支付
            if (Objects.equals(esOrderBO.getPreSaleType(), PreSaleType.DEPOSIT.value()) && Objects.equals(esOrderBO.getStatus(), OrderStatus.WAIT_BALANCE.value())) {
                return 0;
            }
        }
        return payInfoMapper.isPay(orderIds, userId, sysType, payEntry);
    }

    @Override
    public void markerRefund(Long payId) {
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setPayStatus(PayStatus.REFUND.value());
        payInfoMapper.update(payInfo);
    }

    @Override
    public void update(PayInfo payInfo) {
        payInfoMapper.update(payInfo);
    }

    @Override
    public List<PayInfo> listByOrderIds(List<Long> orderIds) {
        return payInfoMapper.listByOrderIds(orderIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PayInfoBO recharge(Long userId, RechargePayInfoDTO payParam) {

        // 支付单号
        ServerResponseEntity<Long> segmentIdResponse = segmentFeignClient.getSegmentIdWithDateTime(DistributedIdKey.MALL4CLOUD_PAY, userId);
        if (!segmentIdResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        Long payId = segmentIdResponse.getData();
        Long rechargeLogId;

        boolean isShopUser = false;
        // 充值信息
        ServerResponseEntity<Long> payAmountResponse;
        if (Objects.equals(AuthUserContext.get().getSysType(), SysTypeEnum.MULTISHOP.value())) {
            if (Objects.isNull(payParam.getShopWalletLogId())) {
                throw new LuckException("请求参数错误");
            }
            isShopUser = true;
            rechargeLogId = payParam.getShopWalletLogId();
            payAmountResponse = shopWalletLogFeignClient.getPayAmount(rechargeLogId);
        } else if (Objects.equals(AuthUserContext.get().getSysType(), SysTypeEnum.ORDINARY.value())) {
            if (Objects.isNull(payParam.getBalanceLogId())) {
                throw new LuckException("请求参数错误");
            }
            rechargeLogId = payParam.getBalanceLogId();
            payAmountResponse = userBalanceLogClient.getPayAmount(rechargeLogId);
        } else if (payParam.getShopId() != null) {
            if (Objects.isNull(payParam.getShopWalletLogId())) {
                throw new LuckException("请求参数错误");
            }
            isShopUser = true;
            rechargeLogId = payParam.getShopWalletLogId();
            payAmountResponse = shopWalletLogFeignClient.getPayAmount(rechargeLogId);
        } else {
            throw new LuckException("你没有权限进行此操作");
        }

        if (!payAmountResponse.isSuccess()) {
            throw new LuckException(payAmountResponse.getMsg());
        }
        Long payAmount = payAmountResponse.getData();
        if (payAmount == null || payAmount < 1) {
            throw new LuckException("充值金额有误");
        }

        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setUserId(userId);
        payInfo.setPayAmount(payAmount);
        payInfo.setPayScore(0L);
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setSysType(AuthUserContext.get().getSysType());
        payInfo.setPayType(payParam.getPayType());
        payInfo.setPayEntry(PayEntry.RECHARGE.value());
        payInfo.setVersion(0);
        // 充值id
        payInfo.setOrderIds(String.valueOf(rechargeLogId));

        // 保存预支付信息
        payInfoMapper.save(payInfo);

        PayInfoBO payInfoDto = new PayInfoBO();
        payInfoDto.setPayId(payId);
        payInfoDto.setPayAmount(payAmount);
        payInfoDto.setBody(isShopUser ? "商家余额充值订单" : "商城余额充值订单");
        return payInfoDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doQrCodePayShop(Long userId, RechargePayInfoDTO payParam) {

        // 虚拟收款码支付单号
        ServerResponseEntity<Long> segmentIdResponse = segmentFeignClient.getSegmentIdWithDateTime(DistributedIdKey.MALL4CLOUD_QRCODEPAY, payParam.getShopId());
        if (!segmentIdResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        Long payId = segmentIdResponse.getData();
        Long rechargeLogId;
        // 充值信息
        ServerResponseEntity<Long> payAmountResponse;
        if (payParam.getShopId() != null) {
            if (Objects.isNull(payParam.getShopWalletLogId())) {
                throw new LuckException("请求参数错误");
            }
            rechargeLogId = payParam.getShopWalletLogId();
            payAmountResponse = shopWalletLogFeignClient.getPayAmount(rechargeLogId);
        } else {
            throw new LuckException("你没有权限进行此操作");
        }

        if (!payAmountResponse.isSuccess()) {
            throw new LuckException(payAmountResponse.getMsg());
        }
        Long payAmount = payAmountResponse.getData();
        if (payAmount == null || payAmount < 1) {
            throw new LuckException("充值金额有误");
        }
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setUserId(userId);
        payInfo.setPayAmount(payAmount);
        payInfo.setPayScore(0L);
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setSysType(AuthUserContext.get().getSysType());
        payInfo.setPayType(payParam.getPayType());
        payInfo.setPayEntry(PayEntry.RECHARGE.value());
        payInfo.setVersion(0);
        // 充值id
        payInfo.setOrderIds(String.valueOf(rechargeLogId));
        // 保存预支付信息
        payInfoMapper.save(payInfo);
        // 发送消息，订单支付成功
        SendStatus   sendStatus = shopRechargeNotifyTemplate.syncSend(RocketMqConstant.SHOP_RECHARGE_NOTIFY_TOPIC, new GenericMessage<>(new RechargeNotifyBO(rechargeLogId, payInfo.getPayType(), payInfo.getPayId()))).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，因为订单回调会有多次，几乎不可能每次都无法发送出去，发的出去无所谓因为接口是幂等的
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void rechargeSuccess(PayInfoResultBO payInfoResult, PayType payType, Long rechargeLogId, Integer sysType) {
        // 标记为支付成功状态
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payInfoResult.getPayId());
        payInfo.setBizPayNo(payInfoResult.getBizPayNo());
        payInfo.setCallbackContent(payInfoResult.getCallbackContent());
        payInfo.setCallbackTime(new Date());
        payInfo.setPayStatus(PayStatus.PAYED.value());
        payInfoMapper.update(payInfo);
        SendStatus sendStatus;
        // 发送消息，订单支付成功
        if (Objects.equals(sysType, SysTypeEnum.MULTISHOP.value())) {
            sendStatus = shopRechargeNotifyTemplate.syncSend(RocketMqConstant.SHOP_RECHARGE_NOTIFY_TOPIC, new GenericMessage<>(new RechargeNotifyBO(rechargeLogId, payType.value(), payInfo.getPayId()))).getSendStatus();
        } else if (Objects.equals(sysType, SysTypeEnum.ORDINARY.value())) {
            sendStatus = userRechargeNotifyTemplate.syncSend(RocketMqConstant.USER_RECHARGE_NOTIFY_TOPIC, new GenericMessage<>(new RechargeNotifyBO(rechargeLogId, payType.value(), payInfo.getPayId()))).getSendStatus();
        } else {
            return;
        }
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，因为订单回调会有多次，几乎不可能每次都无法发送出去，发的出去无所谓因为接口是幂等的
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public PayInfoBO vipBuy(Long userId, BuyVipPayInfoDTO payParam) {
        // 支付单号
        ServerResponseEntity<Long> segmentIdResponse = segmentFeignClient.getSegmentIdWithDateTime(DistributedIdKey.MALL4CLOUD_PAY, userId);
        if (!segmentIdResponse.isSuccess()) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
        Long payId = segmentIdResponse.getData();
        Long userLevelLogId = payParam.getUserLevelLogId();

        // 充值信息
        ServerResponseEntity<Long> payAmountResponse = userLevelLogClient.getPayAmount(userLevelLogId);
        if (!payAmountResponse.isSuccess()) {
            throw new LuckException(payAmountResponse.getMsg());
        }
        Long payAmount = payAmountResponse.getData();
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payId);
        payInfo.setUserId(userId);
        payInfo.setPayAmount(payAmount);
        payInfo.setPayScore(0L);
        payInfo.setPayStatus(PayStatus.UNPAY.value());
        payInfo.setSysType(AuthUserContext.get().getSysType());
        payInfo.setPayType(payParam.getPayType());
        payInfo.setPayEntry(PayEntry.VIP.value());
        payInfo.setVersion(0);
        // 充值id
        payInfo.setOrderIds(String.valueOf(userLevelLogId));
        // 保存预支付信息
        payInfoMapper.save(payInfo);
        PayInfoBO payInfoDto = new PayInfoBO();
        payInfoDto.setBody("商城VIP订购订单");
        payInfoDto.setPayAmount(payAmount);
        payInfoDto.setPayId(payId);
        return payInfoDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void buyVipSuccess(PayInfoResultBO payInfoResult, PayType payType, Long userLevelLogId) {
        // 标记为支付成功状态
        PayInfo payInfo = new PayInfo();
        payInfo.setPayId(payInfoResult.getPayId());
        payInfo.setBizPayNo(payInfoResult.getBizPayNo());
        payInfo.setCallbackContent(payInfoResult.getCallbackContent());
        payInfo.setCallbackTime(new Date());
        payInfo.setPayStatus(PayStatus.PAYED.value());
        payInfoMapper.update(payInfo);

        // 发送消息，订单支付成功
        SendStatus sendStatus = buyVipNotifyTemplate.syncSend(RocketMqConstant.BUY_VIP_NOTIFY_TOPIC, new GenericMessage<>(new BuyVipNotifyBO(userLevelLogId, payType.value(), payInfo.getPayId()))).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            // 消息发不出去就抛异常，因为订单回调会有多次，几乎不可能每次都无法发送出去，发的出去无所谓因为接口是幂等的
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    @Override
    public AccountDetailVO getIncomeAccountDetail(Date startTime, Date endTime, String shopName) {
        ServerResponseEntity<AccountOrderDetailVO> orderResponse = orderFeignClient.getAccountOrderDetail(startTime, endTime, shopName, null);
        if (!orderResponse.isSuccess()) {
            throw new LuckException(orderResponse.getMsg());
        }
        ServerResponseEntity<ShopAccountDetailVO> userResponse = userBalanceLogClient.getPlatformAccountDetail(startTime, endTime);
        if (!userResponse.isSuccess()) {
            throw new LuckException(userResponse.getMsg());
        }
        ShopAccountDetailVO platformAccountInfo = userResponse.getData();
        AccountDetailVO accountDetailVO = mapperFacade.map(orderResponse.getData(), AccountDetailVO.class);

        if (Objects.isNull(accountDetailVO)) {
            accountDetailVO = new AccountDetailVO();

        }
        accountDetailVO.setAlipayAmount((Objects.isNull(platformAccountInfo.getAlipayAmount()) ? 0L : platformAccountInfo.getAlipayAmount()) + (Objects.isNull(accountDetailVO.getAlipayAmount()) ? 0L : accountDetailVO.getAlipayAmount()));

        accountDetailVO.setWechatAmount((Objects.isNull(platformAccountInfo.getWechatAmount()) ? 0L : platformAccountInfo.getWechatAmount()) + (Objects.isNull(accountDetailVO.getWechatAmount()) ? 0L : accountDetailVO.getWechatAmount()));
        accountDetailVO.setAlipayAmount((Objects.isNull(platformAccountInfo.getAlipayAmount()) ? 0L : platformAccountInfo.getAlipayAmount()) + (Objects.isNull(accountDetailVO.getAlipayAmount()) ? 0L : accountDetailVO.getAlipayAmount()));

        accountDetailVO.setBalanceAmount((Objects.isNull(platformAccountInfo.getBalanceAmount()) ? 0L : platformAccountInfo.getBalanceAmount()) + (Objects.isNull(accountDetailVO.getBalanceAmount()) ? 0L : accountDetailVO.getBalanceAmount()));

        accountDetailVO.setScoreCount((Objects.isNull(platformAccountInfo.getScoreCount()) ? 0L : platformAccountInfo.getScoreCount()) + (Objects.isNull(accountDetailVO.getScoreCount()) ? 0L : accountDetailVO.getScoreCount()));

        accountDetailVO.setWechatPercent(0.00);
        accountDetailVO.setAlipayPercent(0.00);
        accountDetailVO.setBalancePercent(0.00);
        accountDetailVO.setTotal(0L);
        getTotal(accountDetailVO);
        return accountDetailVO;
    }

    @Override
    public AccountDetailVO getPlatformIncomeAccountDetail(Date startTime, Date endTime) {
        // 获取平台信息
        ServerResponseEntity<ShopAccountDetailVO> userResponse = userBalanceLogClient.getPlatformAccountDetail(startTime, endTime);
        if (!userResponse.isSuccess()) {
            throw new LuckException(userResponse.getMsg());
        }
        ShopAccountDetailVO platformAccountInfo = userResponse.getData();
        ServerResponseEntity<AccountOrderDetailVO> platformOrderResponse = orderFeignClient.getAccountOrderDetail(startTime, endTime, "", Constant.PLATFORM_SHOP_ID);
        if (!platformOrderResponse.isSuccess()) {
            throw new LuckException(platformOrderResponse.getMsg());
        }
        AccountOrderDetailVO accountOrderDetailVO = platformOrderResponse.getData();
        AccountDetailVO platformAccountDetail = new AccountDetailVO();
        platformAccountDetail.setAlipayAmount((Objects.isNull(platformAccountInfo.getAlipayAmount()) ? 0L : platformAccountInfo.getAlipayAmount()) + (Objects.isNull(accountOrderDetailVO.getAlipayAmount()) ? 0L : accountOrderDetailVO.getAlipayAmount()));
        platformAccountDetail.setWechatAmount((Objects.isNull(platformAccountInfo.getWechatAmount()) ? 0L : platformAccountInfo.getWechatAmount()) + (Objects.isNull(accountOrderDetailVO.getWechatAmount()) ? 0L : accountOrderDetailVO.getWechatAmount()));
        platformAccountDetail.setBalanceAmount((Objects.isNull(platformAccountInfo.getBalanceAmount()) ? 0L : platformAccountInfo.getBalanceAmount()) + (Objects.isNull(accountOrderDetailVO.getBalanceAmount()) ? 0L : accountOrderDetailVO.getBalanceAmount()));
        platformAccountDetail.setScoreCount((Objects.isNull(platformAccountInfo.getScoreCount()) ? 0L : platformAccountInfo.getScoreCount()) + (Objects.isNull(accountOrderDetailVO.getScoreCount()) ? 0L : accountOrderDetailVO.getScoreCount()));
        platformAccountDetail.setTotal(platformAccountDetail.getAlipayAmount() + platformAccountDetail.getBalanceAmount() + platformAccountDetail.getWechatAmount());
        return platformAccountDetail;
    }

    private void getTotal(AccountDetailVO accountDetailVO) {
        Long wechatAmount = Objects.isNull(accountDetailVO.getWechatAmount()) ? 0L : accountDetailVO.getWechatAmount();
        Long alipayAmount = Objects.isNull(accountDetailVO.getAlipayAmount()) ? 0L : accountDetailVO.getAlipayAmount();
        Long balanceAmount = Objects.isNull(accountDetailVO.getBalanceAmount()) ? 0L : accountDetailVO.getBalanceAmount();
        long total = wechatAmount + alipayAmount + balanceAmount;
        accountDetailVO.setWechatPercent(Arith.div(wechatAmount.doubleValue(), (double) total, 4));
        accountDetailVO.setAlipayPercent(Arith.div(alipayAmount.doubleValue(), (double) total, 4));
        accountDetailVO.setBalancePercent(Arith.div(balanceAmount.doubleValue(), (double) total, 4));
        accountDetailVO.setTotal(total);
    }

    @Override
    public PageVO<PayInfoVO> getPayInfoPage(PageDTO pageDTO, AccountSearchDTO accountSearchDTO) {
        PageVO<PayInfoVO> pageVO = new PageVO<>();
        if (Objects.equals(accountSearchDTO.getFinanceType(), FinanceType.RECHARGE.value()) || Objects.equals(accountSearchDTO.getFinanceType(), FinanceType.LEVEL.value())) {
            ServerResponseEntity<PageVO<UserPayInfoVO>> userResponse = userBalanceLogClient.pageUserPayInfo(accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getFinanceType(), pageDTO.getPageSize(), pageDTO.getPageNum());
            if (!userResponse.isSuccess()) {
                throw new LuckException(userResponse.getMsg());
            }
            PageVO<UserPayInfoVO> userResponseData = userResponse.getData();
            pageVO.setPages(userResponseData.getPages());
            pageVO.setTotal(userResponseData.getTotal());
            pageVO.setList(mapperFacade.mapAsList(userResponseData.getList(), PayInfoVO.class));
        } else {
            ServerResponseEntity<PageShopAccountOrderVO> orderResponse = orderFeignClient.listOrderPayInfo(accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getShopId(), null, pageDTO.getPageSize(), pageDTO.getPageNum());
            if (!orderResponse.isSuccess()) {
                throw new LuckException(orderResponse.getMsg());
            }
            pageVO.setTotal(orderResponse.getData().getTotal());
            pageVO.setList(mapperFacade.mapAsList(orderResponse.getData().getPayInfoList(), PayInfoVO.class));
            pageVO.setPages(PageUtil.getPages(orderResponse.getData().getTotal(), pageDTO.getPageSize()));
        }
        return pageVO;
    }

    @Override
    public void excelPayInfo(HttpServletResponse response, AccountSearchDTO accountSearchDTO) {
        accountSearchDTO.setFinanceType(FinanceType.ORDER.value());
        ServerResponseEntity<PageShopAccountOrderVO> orderResponse = orderFeignClient.listOrderPayInfo(accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), null, accountSearchDTO.getShopName(), null, null);
        if (!orderResponse.isSuccess()) {
            throw new LuckException(orderResponse.getMsg());
        }
        List<PayInfoVO> orderPayInfoList = mapperFacade.mapAsList(orderResponse.getData().getPayInfoList(), PayInfoVO.class);
        accountSearchDTO.setFinanceType(FinanceType.RECHARGE.value());
        ServerResponseEntity<List<UserPayInfoVO>> balanceResponse = userBalanceLogClient.listUserPayInfo(accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getFinanceType());
        if (!balanceResponse.isSuccess()) {
            throw new LuckException(balanceResponse.getMsg());
        }
        List<PayInfoVO> rechargePayInfoList = mapperFacade.mapAsList(balanceResponse.getData(), PayInfoVO.class);
        accountSearchDTO.setFinanceType(FinanceType.LEVEL.value());
        ServerResponseEntity<List<UserPayInfoVO>> levelResponse = userBalanceLogClient.listUserPayInfo(accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getFinanceType());
        if (!levelResponse.isSuccess()) {
            throw new LuckException(levelResponse.getMsg());
        }
        List<PayInfoVO> levelPayInfoList = mapperFacade.mapAsList(levelResponse.getData(), PayInfoVO.class);

        Map<Integer, String[]> map = new HashMap<>(8);
        ExcelWriter excelWriter = null;
        try {
            // 先执行合并策略
            ExcelWriterBuilder excelWriterMerge = ExcelUtil.getExcelWriterMerge(response, PayInfoExcelVO.EXCEL_NAME, PayInfoExcelVO.MERGE_ROW_INDEX, PayInfoExcelVO.MERGE_COLUMN_INDEX);
            excelWriter = ExcelUtil.getExcelModel(excelWriterMerge, map, Constant.START_ROW).build();
            // 业务代码
            writeExcel(orderPayInfoList, FinanceType.ORDER.str(), excelWriter, FinanceType.ORDER.value());
            // 余额充值
            writeExcel(rechargePayInfoList, FinanceType.RECHARGE.str(), excelWriter, FinanceType.RECHARGE.value());
            // 会员购买
            writeExcel(levelPayInfoList, FinanceType.LEVEL.str(), excelWriter, FinanceType.LEVEL.value());
        } catch (Exception e) {
            log.error("导出财务对账收入报表出错", e);
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    private Set<String> getExcelColumn(Integer financeType) {
        Set<String> column = new HashSet<>();
        if (Objects.equals(financeType, FinanceType.RECHARGE.value())) {
            // 余额充值没有支付积分和余额金额和店铺名称
            column.add("payScore");
            column.add("balanceAmount");
            column.add("shopName");
        }
        if (Objects.equals(financeType, FinanceType.LEVEL.value())) {
            // 会员购买没有支付积分和店铺名称
            column.add("payScore");
            column.add("shopName");
        }
        return column;
    }

    private void writeExcel(List<PayInfoVO> payInfoList, String type, ExcelWriter excelWriter, Integer financeType) {
        Set<String> excelColumn = getExcelColumn(financeType);
        List<PayInfoExcelVO> payInfoExcelList = getExcelList(payInfoList);
        if (CollUtil.isNotEmpty(payInfoExcelList)) {
            payInfoExcelList.add(new PayInfoExcelVO());
        }
        WriteSheet sheetWriter = EasyExcel.writerSheet(type).head(PayInfoExcelVO.class).excludeColumnFieldNames(excelColumn).build();
        excelWriter.write(payInfoExcelList, sheetWriter);
    }

    private List<PayInfoExcelVO> getExcelList(List<PayInfoVO> payInfoList) {
        List<PayInfoExcelVO> payInfoExcelList = new ArrayList<>();
        int index = 1;
        for (PayInfoVO payInfoVO : payInfoList) {
            PayInfoExcelVO payInfoExcelVO = new PayInfoExcelVO();
            payInfoExcelVO.setSeq(String.valueOf(index));
            payInfoExcelVO.setShopName(payInfoVO.getShopName());
            payInfoExcelVO.setPayId(payInfoVO.getPayId());
            payInfoExcelVO.setOrderIds(payInfoVO.getOrderIds());
            payInfoExcelVO.setPayEntry(PayEntry.getPayTypeName(payInfoVO.getPayEntry()));
            payInfoExcelVO.setPayType(PayType.getPayTypeName(payInfoVO.getPayType()));
            payInfoExcelVO.setPayScore(Objects.isNull(payInfoVO.getScoreCount()) ? "0" : payInfoVO.getScoreCount().toString());
            payInfoExcelVO.setAlipayAmount(PriceUtil.toDecimalPrice(payInfoVO.getAlipayAmount()).toString());
            payInfoExcelVO.setWechatAmount(PriceUtil.toDecimalPrice(payInfoVO.getWechatAmount()).toString());
            payInfoExcelVO.setBalanceAmount(PriceUtil.toDecimalPrice(payInfoVO.getBalanceAmount()).toString());
            payInfoExcelVO.setPayTime(payInfoVO.getPayTime());
            payInfoExcelList.add(payInfoExcelVO);
            index++;
        }
        return payInfoExcelList;
    }

    @Override
    public PageVO<ShopAccountDetailVO> pageIncomeAccountDetail(PageDTO pageDTO, AccountSearchDTO accountSearchDTO) {
        // 获取店铺信息
        ServerResponseEntity<PageShopAccountOrderVO> orderResponse = orderFeignClient.listShopAccountDetail(accountSearchDTO.getStartTime(), accountSearchDTO.getEndTime(), accountSearchDTO.getShopName(), pageDTO.getPageSize(), pageDTO.getPageNum());
        if (!orderResponse.isSuccess()) {
            throw new LuckException(orderResponse.getMsg());
        }
        List<ShopAccountOrderDetailVO> shopList = orderResponse.getData().getShopList();
        List<ShopAccountDetailVO> result = mapperFacade.mapAsList(shopList, ShopAccountDetailVO.class);
        PageVO<ShopAccountDetailVO> shopPage = new PageVO<>();
        shopPage.setTotal(orderResponse.getData().getTotal());
        shopPage.setList(result);
        shopPage.setPages(PageUtil.getPages(orderResponse.getData().getTotal(), pageDTO.getPageSize()));
        return shopPage;
    }
}
